/*
 * @Author: wuqingchun
 * @Date: 2024-06-22 14:38:55
 * @Description: 
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-06-23 16:11:37
 */

#include <unistd.h>

#include "http_conn.h"

CHTTPConnection::CHTTPConnection(CHTTPLogger& refLogger, CHTTPConnFactory& refFactory, 
                                 CHTTPEventPoller& refPoller, int iSock, bool bIsListener):
    m_refLogger(refLogger),
    m_refFactory(refFactory),
    m_refPoller(refPoller),
    m_iSockFd(iSock),
    m_bIsListener(bIsListener)
{

}

int CHTTPConnection::HandleIn()
{
    int32_t iErr;

    if (m_bIsListener)
    {
        IHTTPEvent* pEvent = m_refFactory.CreateAcceptor(*this);
        if (pEvent != nullptr)
        {
            iErr = m_refPoller.AddEvent(*pEvent, EEventType::EVENT_IN);
            if (iErr != HTTP_OK)
            {
                HTTP_ERROR(iErr, "AddEvent error");
            }
        }
    }
    else
    {
        iErr = __Recv();
        if (iErr == HTTP_FAILED)
        {
            HandleError();
        }
        else
        {
            HTTP_INFO("Received message, length=%ld, sockfd=%d", m_ulDataLen, m_iSockFd);

            if (m_pobjParser != nullptr)
            {
                HTTP_BUF_S stBuf;
                stBuf.pcStart = m_acBuf;
                stBuf.pcEnd = m_acBuf + m_ulDataLen;
                m_pobjParser->OnRecv(*this, stBuf);
            }
        }
    }
}

int CHTTPConnection::HandleOut()
{

}

void CHTTPConnection::HandleError() 
{
    HTTP_INFO("Connection closed, sockfd=%d", m_iSockFd);
    
    close(m_iSockFd);
    m_iSockFd = -1;
}

int CHTTPConnection::GetEventFd() 
{
    return m_iSockFd;
}

int CHTTPConnection::Send(const HTTP_BUF_S& refData)
{
    int iErr;

    m_listSndBuf.emplace_back(refData);

    for (auto& refItem : m_listSndBuf)
    {
        iErr = __Send(refItem);
        if (iErr != HTTP_OK)
        {
            m_listSndBuf.emplace_front(refItem);
            iErr = m_refPoller.AddEvent(*this, EEventType::EVENT_OUT);
            break;
        }
    }

    return iErr;
}

int32_t CHTTPConnection::__RecvOnce(HTTP_STRING_S& refInBuf)
{
    int32_t iErr = HTTP_OK;

    ssize_t lLen = recv(m_iSockFd, refInBuf.pcStr, refInBuf.ulLen, 0);
    if (lLen == -1)
    {
        refInBuf.ulLen = 0;
        if (errno == EINTR)
        {
            // 需要重新读
            iErr = HTTP_AGAIN;
        }
        else if (errno == EAGAIN || errno == EWOULDBLOCK)
        {
            // 没有数据
            iErr = HTTP_NOT_READY;
        }
    }
    else if (lLen == 0)
    {
        // 连接关闭
        iErr = HTTP_FAILED;
    }
    else 
    {
        if (lLen == refInBuf.ulLen)
        {
            iErr = HTTP_AGAIN;
        }

        refInBuf.ulLen = lLen;
    }

    return iErr;
}

int32_t CHTTPConnection::__Recv()
{
    HTTP_STRING_S stBuf;

    stBuf.pcStr = m_acBuf;
    stBuf.ulLen = 8;
    int32_t iErr;

    while ((iErr = __RecvOnce(stBuf)) == HTTP_AGAIN)
    {
        m_ulDataLen += stBuf.ulLen;
        stBuf.pcStr = m_acBuf + m_ulDataLen;
        stBuf.ulLen = 8;
    }

    if (iErr == HTTP_OK)
    {
        m_ulDataLen += stBuf.ulLen;
    }

    return iErr;
}


int32_t CHTTPConnection::__Send(HTTP_BUF_S& refData)
{
    int32_t iErr = HTTP_OK;

    size_t ulDataLen = refData.pcEnd - refData.pcStart;
    do {
        ssize_t lLen = send(m_iSockFd, refData.pcStart, refData.pcEnd - refData.pcStart, 0);
        if (lLen == -1)
        {
            if (errno == EINTR)
            {
                // 需要重新发送
                iErr = HTTP_AGAIN;
            }
            else if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                // 发送缓冲区满
                iErr = HTTP_NOT_READY;
            }
        }
        else if (lLen < ulDataLen)
        {
            iErr = HTTP_AGAIN;
            refData.pcStart = refData.pcEnd + lLen;
            ulDataLen -= lLen;
        }
    } while (iErr == HTTP_AGAIN);

    return iErr;
}